package rursu.parser;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;

import rursu.business.pojo.Country;
import rursu.business.pojo.LanguageSpoken;
import rursu.business.pojo.MovieCategory;
import rursu.business.pojo.MovieDetails;
import rursu.business.pojo.MovieImage;
import rursu.business.pojo.Person;
import rursu.business.pojo.Studio;
import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.sax.StartElementListener;
import android.util.Log;
import android.util.Xml;

public class MovieDetailsSAXParser implements
		MovieDetailsParser {

	private final String LOGGER_TAG = MovieDetailsSAXParser.class.getCanonicalName();
	
	// names of the XML tags
	private static final String ROOT = "OpenSearchDescription";
	private static final String MOVIES = "movies";
	private static final String MOVIE = "movie";
	private static final String POPULARITY = "popularity";
	private static final String TRANSLATED = "translated";
	private static final String ADULT = "adult";
	private static final String LANGUAGE = "language";
	private static final String ORIGINAL_NAME = "original_name";
	private static final String NAME = "name";
	private static final String ALTERNATIVE_NAME = "alternative_name";
	private static final String TYPE = "type";
	private static final String ID = "id";
	private static final String IMDB_ID = "imdb_id";
	private static final String URL = "url";
	private static final String OVERVIEW = "overview";
	private static final String VOTES = "votes";
	private static final String RATING = "rating";
	private static final String TAGLINE = "tagline";
	private static final String CERTIFICATION = "certification";
	private static final String RELEASED = "released";
	private static final String RUNTIME = "runtime";
	private static final String BUDGET = "budget";
	private static final String REVENUE = "revenue";
	private static final String HOMEPAGE = "homepage";
	private static final String TRAILER = "trailer";

	private static final String CATEGORIES = "categories";
	private static final String CATEGORY = "category";
	private static final String CATEGORY_TYPE = "type";
	private static final String CATEGORY_NAME = "name";
	private static final String CATEGORY_URL = "url";
	private static final String CATEGORY_ID = "id";

	private static final String KEYWORDS = "keywords";
	private static final String KEYWORD = "keyword";
	private static final String KEYWORD_NAME = "name";

	private static final String STUDIOS = "studios";
	private static final String STUDIO = "studio";
	private static final String STUDIO_NAME = "name";
	private static final String STUDIO_URL = "url";
	private static final String STUDIO_ID = "id";

	private static final String LANGUAGES_SPOKEN = "languages_spoken";
	private static final String LANGUAGE_SPOKEN = "language_spoken";
	private static final String LANGUAGE_SPOKEN_CODE = "code";
	private static final String LANGUAGE_SPOKEN_NAME = "name";
	private static final String LANGUAGE_SPOKEN_NATIVE_NAME = "native_name";

	private static final String COUNTRIES = "countries";
	private static final String COUNTRY = "country";
	private static final String COUNTRY_NAME = "name";
	private static final String COUNTRY_CODE = "code";
	private static final String COUNTRY_URL = "url";

	private static final String IMAGES = "images";
	private static final String IMAGE = "image";
	private static final String IMAGE_ATTRIBUTE_TYPE = "type";
	private static final String IMAGE_ATTRIBUTE_URL = "url";
	private static final String IMAGE_ATTRIBUTE_SIZE = "size";
	private static final String IMAGE_ATTRIBUTE_WIDTH = "width";
	private static final String IMAGE_ATTRIBUTE_HIGHT = "height";
	private static final String IMAGE_ATTRIBUTE_ID = "id";

	private static final String CAST = "cast";
	private static final String PERSON = "person";
	private static final String PERSON_NAME = "name";
	private static final String PERSON_CHARACTER = "character";
	private static final String PERSON_JOB = "job";
	private static final String PERSON_ID = "id";
	private static final String PERSON_THUMB = "thumb";
	private static final String PERSON_DEPARTMENT = "department";
	private static final String PERSON_URL = "url";
	private static final String PERSON_ORDER = "order";
	private static final String PERSON_CAST_ID = "cast_id";

	private static final String VERSION = "version";
	private static final String LAST_MODIFIED_AT = "last_modified_at";
	
	public MovieDetails parse(InputStream inputStream) {
		
		final MovieDetails movieDetails = new MovieDetails();
		final List<MovieImage> movieImagesList = new ArrayList<MovieImage>();
		final List<MovieCategory> movieCategoryList = new ArrayList<MovieCategory>();
		final List<String> movieKeywords = new ArrayList<String>();
		final List<Studio> movieStudios = new ArrayList<Studio>();
		final List<LanguageSpoken> movieLanguagesSpoken = new ArrayList<LanguageSpoken>();
		final List<Country> movieCountries = new ArrayList<Country>();
		final List<Person> cast = new ArrayList<Person>();

		RootElement root = new RootElement(ROOT);

		Element moviesElement = root.getChild(MOVIES);

		Element movieElement = moviesElement.getChild(MOVIE);

		movieElement.getChild(POPULARITY).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setPopularity(Float.parseFloat(body));
						} else {
							movieDetails.setPopularity(0);
						}

					}
				});

		movieElement.getChild(TRANSLATED).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setTranslated(Boolean
									.parseBoolean(body));
						} else {
							movieDetails.setTranslated(false);
						}

					}
				});

		movieElement.getChild(ADULT).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setAdult(Boolean.parseBoolean(body));
						} else {
							movieDetails.setAdult(false);
						}

					}
				});

		movieElement.getChild(LANGUAGE).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setLanguage(body);

					}
				});

		movieElement.getChild(ORIGINAL_NAME).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setOriginalName(body);

					}
				});

		movieElement.getChild(NAME).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setName(body);

					}
				});

		movieElement.getChild(ALTERNATIVE_NAME).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setAlternativeName(body);

					}
				});

		movieElement.getChild(TYPE).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setType(body);

					}
				});

		movieElement.getChild(ID).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {

						if (body.length() != 0) {
							movieDetails.setId(Integer.parseInt(body));
						} else {
							movieDetails.setId(0);
						}

					}
				});

		movieElement.getChild(IMDB_ID).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setImdbId(body);
					}
				});

		movieElement.getChild(URL).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setUrl(body);

					}
				});

		movieElement.getChild(OVERVIEW).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setOverview(body);

					}
				});

		movieElement.getChild(VOTES).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setVotes(Integer.parseInt(body));
						} else {
							movieDetails.setVotes(0);
						}

					}
				});

		movieElement.getChild(RATING).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {

						if (body.length() != 0) {
							movieDetails.setRating(Float.parseFloat(body));
						} else {
							movieDetails.setRating(0);
						}
					}
				});

		movieElement.getChild(TAGLINE).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setTagline(body);

					}
				});

		movieElement.getChild(CERTIFICATION).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setCertification(body);

					}
				});

		movieElement.getChild(RELEASED).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setReleased(body);

					}
				});

		movieElement.getChild(RUNTIME).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setRuntime(Integer.parseInt(body));
						} else {
							movieDetails.setRuntime(0);
						}

					}
				});

		movieElement.getChild(BUDGET).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setBudget(Integer.parseInt(body));
						} else {
							movieDetails.setBudget(0);
						}

					}
				});

		movieElement.getChild(REVENUE).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setRevenue(Integer.parseInt(body));
						} else {
							movieDetails.setRevenue(0);
						}

					}
				});

		movieElement.getChild(HOMEPAGE).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setHomepage(body);

					}
				});

		movieElement.getChild(TRAILER).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setTrailer(body);

					}
				});

		movieElement.getChild(VERSION).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						if (body.length() != 0) {
							movieDetails.setVersion(Integer.parseInt(body));
						} else {
							movieDetails.setVersion(0);
						}

					}
				});

		movieElement.getChild(LAST_MODIFIED_AT).setEndTextElementListener(
				new EndTextElementListener() {

					public void end(String body) {
						movieDetails.setLastModified(body);

					}
				});

		// Images parsing

		Element movieImagesElement = movieElement.getChild(IMAGES);
		movieImagesElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<MovieImage> images = new ArrayList<MovieImage>();

				images.addAll(movieImagesList);

				movieDetails.setImages(images);
				movieImagesList.clear();
			}
		});

		Element imageElement = movieImagesElement.getChild(IMAGE);
		imageElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {

				MovieImage image = new MovieImage();
				
				// parsing width
				int width = 0;
				try {
					width = Integer.parseInt(attributes.getValue(IMAGE_ATTRIBUTE_WIDTH));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}
				
				image.setWidth(width);
				
				// parsing height
				int height = 0;
				try {
					height = Integer.parseInt(attributes.getValue(IMAGE_ATTRIBUTE_HIGHT));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}
				
				image.setHeight(height);

				// parsing id
				image.setId(attributes.getValue(IMAGE_ATTRIBUTE_ID));
				
				// parsing size
				image.setSize(attributes.getValue(IMAGE_ATTRIBUTE_SIZE));
				
				// parsing type
				image.setType(attributes.getValue(IMAGE_ATTRIBUTE_TYPE));
				
				// parsing url
				image.setUrl(attributes.getValue(IMAGE_ATTRIBUTE_URL));
				
				movieImagesList.add(image);
			}
		});

		// Categories parsing

		Element movieCategoryElement = movieElement.getChild(CATEGORIES);
		movieCategoryElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<MovieCategory> categories = new ArrayList<MovieCategory>();

				categories.addAll( movieCategoryList );

				movieDetails.setCategories(categories);
				movieCategoryList.clear();
			}
		});

		Element categoryElement = movieCategoryElement.getChild(CATEGORY);
		categoryElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {

				MovieCategory categoryItem = new MovieCategory();

				int id = 0;
				try {
					id = Integer.parseInt( attributes.getValue(CATEGORY_ID) );
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}
				
				categoryItem.setId(id);				
				
				categoryItem.setName(attributes.getValue(CATEGORY_NAME));
				categoryItem.setType(attributes.getValue(CATEGORY_TYPE));
				categoryItem.setUrl(attributes.getValue(CATEGORY_URL));

				movieCategoryList.add(categoryItem);

			}
		});

		// Keywords parsing

		Element keywordsElement = movieElement.getChild(KEYWORDS);
		keywordsElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<String> keywords = new ArrayList<String>();

				keywords.addAll(movieKeywords);

				movieKeywords.clear();
				movieDetails.setKeywords(keywords);
			}

		});

		Element keywordElement = keywordsElement.getChild(KEYWORD);
		keywordElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {
				
				// parsing name
				movieKeywords.add( attributes.getValue(KEYWORD_NAME) );
			}
		});

		// Studios parsing

		Element studiosElement = movieElement.getChild(STUDIOS);
		studiosElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<Studio> studios = new ArrayList<Studio>();

				studios.addAll(movieStudios);

				movieStudios.clear();
				movieDetails.setStudios(studios);
			}
		});

		Element studioElement = studiosElement.getChild(STUDIO);
		studioElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {
				
				Studio studio = new Studio();

				// parsing id
				int id = 0;
				try {
					id = Integer.parseInt(attributes.getValue(STUDIO_ID));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}
				
				studio.setId(id);
				
				// parsing name
				studio.setName(attributes.getValue(STUDIO_NAME));
				
				// parsing url
				studio.setUrl(attributes.getValue(STUDIO_URL));

				movieStudios.add(studio);
			}
		});

		// Languages spoken parsing
		Element languagesSpokenElement = movieElement.getChild(LANGUAGES_SPOKEN);
		languagesSpokenElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<LanguageSpoken> languagesSpoken = new ArrayList<LanguageSpoken>();

				languagesSpoken.addAll(movieLanguagesSpoken);

				movieLanguagesSpoken.clear();
				movieDetails.setLanguages(languagesSpoken);
			}
		});

		Element languageSpokenElement = languagesSpokenElement.getChild(LANGUAGE_SPOKEN);
		languageSpokenElement.setStartElementListener(new StartElementListener() {

					public void start(Attributes attributes) {
						
						LanguageSpoken language = new LanguageSpoken();
						
						language.setCode(attributes.getValue(LANGUAGE_SPOKEN_CODE));
						language.setName(attributes.getValue(LANGUAGE_SPOKEN_NAME));
						language.setNativeName(attributes.getValue(LANGUAGE_SPOKEN_NATIVE_NAME));						

						movieLanguagesSpoken.add(language);
					}
				});

		// Countries parsing
		Element countriesElement = movieElement.getChild(COUNTRIES);
		countriesElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<Country> countries = new ArrayList<Country>();

				countries.addAll(movieCountries);

				movieCountries.clear();
				movieDetails.setCountries(countries);
			}
		});

		Element countryElement = countriesElement.getChild(COUNTRY);
		countryElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {
				Country country = new Country();

				country.setCode(attributes.getValue(COUNTRY_CODE));
				country.setName(attributes.getValue(COUNTRY_NAME));
				country.setUrl(attributes.getValue(COUNTRY_URL));

				movieCountries.add(country);
			}
		});

		// Cast parsing
		Element castElement = movieElement.getChild(CAST);
		castElement.setEndElementListener(new EndElementListener() {

			public void end() {
				List<Person> persons = new ArrayList<Person>();

				persons.addAll(cast);

				cast.clear();
				movieDetails.setCast(persons);
			}
		});

		Element personElement = castElement.getChild(PERSON);
		personElement.setStartElementListener(new StartElementListener() {

			public void start(Attributes attributes) {

				Person person = new Person();

				// parsing cast_id
				int castId = 0;
				try {
					castId = Integer.parseInt(attributes.getValue("",
							PERSON_CAST_ID));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}

				person.setCastId(castId);

				// parsing id
				int id = 0;
				try {
					id = Integer.parseInt(attributes.getValue(PERSON_ID));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}

				person.setId(id);

				// parsing order
				int order = 0;
				try {
					order = Integer.parseInt(attributes.getValue(PERSON_ORDER));
				} catch (NumberFormatException e) {
					Log.v(LOGGER_TAG, e.toString());
				}

				person.setOrder(order);

				// parsing name
				person.setName(attributes.getValue(PERSON_NAME));

				// parsing character
				person.setCharacter(attributes.getValue(PERSON_CHARACTER));

				// parsing job
				person.setJob(attributes.getValue(PERSON_JOB));

				// parsing thumb
				person.setThumb(attributes.getValue(PERSON_THUMB));

				// parsing department
				person.setDepartment(attributes.getValue(PERSON_DEPARTMENT));

				// parsing url
				person.setUrl(attributes.getValue(PERSON_URL));

				cast.add(person);
			}
		});

		try {

			Xml.parse(inputStream, Xml.Encoding.UTF_8, root.getContentHandler());
			inputStream.close();

		} catch (Exception e) {

			throw new RuntimeException(e);
		}

		return movieDetails;
	}

}
